﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace BilingualSentSearchEngine
{
    // NOTE: If you change the class name "Service1" here, you must also update the reference to "Service1" in App.config.
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
    [FaultErrorHandler]
    public class BilingualSentSearchService : IBilingualSentSearchService
    {
        static private BilingualSentenceSearch bilingualSentenceSearch;
        static private SentencePairValidation sentencePairValidation;
        static private ChineseUtility.Converter chineseConvert;
        ChineseUtility.WordBreaker chineseWordBreaker;
        ChineseUtility.Synonym chineseSynonym;
        ConciseDict conciseDict;
        TermFormationReader tfr;
        static private DataAnalysis da;
        UserAgent userAgent;

        public BilingualSentSearchService ()
        {
            string strServiceRootPath = System.Configuration.ConfigurationSettings.AppSettings["ServiceRootPath"];
            string strIndexingServiceList = System.Configuration.ConfigurationSettings.AppSettings["IndexingServiceList"];
            string strMaxAccessLimit = System.Configuration.ConfigurationSettings.AppSettings["MaxAccessLimit"];
            string strAccessSpanHours = System.Configuration.ConfigurationSettings.AppSettings["AccessSpanHours"];


            char[] sep;
            string[] astrIndexServiceList;

            sep = new char[1];
            sep[0] = ';';
            astrIndexServiceList = strIndexingServiceList.Split(sep);

            bilingualSentenceSearch = new BilingualSentenceSearch(astrIndexServiceList);
            sentencePairValidation = new SentencePairValidation(strServiceRootPath + @"\BadEnglishSentence.txt");
            chineseWordBreaker = new ChineseUtility.WordBreaker(strServiceRootPath + @"\ChineseDictionary.txt");
            chineseSynonym = new ChineseUtility.Synonym(strServiceRootPath + @"\SynonymDictionary.txt", strServiceRootPath + @"\ChineseDictionary.txt");
            da = new DataAnalysis(strServiceRootPath + @"\DataAnalysis.txt");

            conciseDict = new ConciseDict(strServiceRootPath + @"\engDict.txt", strServiceRootPath + @"\chsDict.txt", strServiceRootPath + @"\dict.idx");
            tfr = new TermFormationReader();
            tfr.Open(strServiceRootPath + @"\WordFormation.idx", strServiceRootPath + @"\WordFormation.txt");


            chineseConvert = new ChineseUtility.Converter();

            userAgent = new UserAgent(int.Parse(strMaxAccessLimit), int.Parse(strAccessSpanHours));

            System.Diagnostics.EventLog.WriteEntry("Constructing BilingualSentSearchService", "BilingualSentenceSearch instance has been created");

        }


        public void ReportWrongSentencePair(string strQuery, string strEnglishSentence, string strChineseSentence)
        {
            sentencePairValidation.AddBadSentencePair(ref strQuery, ref strEnglishSentence, ref strChineseSentence);
        }


        public List<string> GetChineseByEnglish(string strWord)
        {
            return conciseDict.GetChineseByEnglish(strWord);
        }

        public List<string> GetEnglishByChinese(string strWord)
        {
            return conciseDict.GetEnglishByChinese(strWord);
        }

        public List<string> GetTermFormations(string term)
        {
            return tfr.GetTermFormations(term);
        }

        public List<string> SCHS_WordBreaker(string strWord, int maxLength, bool bIgnoreSpace)
        {
            return chineseWordBreaker.ParseString(ref strWord, maxLength, bIgnoreSpace);
        }

        public HashSet<string> GetAllMarkWord(ref string strQuery)
        {
            HashSet<string> hash = new HashSet<string>();
            if (strQuery.Length == 0)
            {
                return hash;
            }

            List<string> termList = chineseWordBreaker.ParseString(ref strQuery, 8, false);
            if (strQuery[0] >= 'a' && strQuery[0] <= 'z')
            {
                //英文query
                foreach (string term in termList)
                {
                    if (hash.Contains(term) == false)
                    {
                        hash.Add(term);
                    }

                    List<string> tList;
                    tList = tfr.GetTermFormations(term);
                    foreach (string s in tList)
                    {
                        if (hash.Contains(s) == false)
                        {
                            hash.Add(s);
                        }

                    }

                    tList = conciseDict.GetChineseByEnglish(term);
                    foreach (string s in tList)
                    {
                        if (hash.Contains(s) == false)
                        {
                            hash.Add(s);
                        }

                    }

                }

            }
            else
            {
                //中文query
                foreach (string term in termList)
                {
                    if (hash.Contains(term) == false)
                    {
                        hash.Add(term);
                    }

                    List<string> tList;
                    tList = chineseSynonym.GetSynonym(term);
                    foreach (string s in tList)
                    {
                        if (hash.Contains(s) == false)
                        {
                            hash.Add(s);
                        }
                    }

                    tList = conciseDict.GetEnglishByChinese(term);
                    foreach (string s in tList)
                    {
                        if (hash.Contains(s) == false)
                        {
                            hash.Add(s);
                        }
                    }
                }

            }

           
            return hash;
        }

        private string LabelChineseSentence(string strSent, ref HashSet<string> hash)
        {
            List<string> strTermSeg;
            strTermSeg = chineseWordBreaker.ParseString(ref strSent, 8, false);
            StringBuilder sb = new StringBuilder(128);
            foreach (string term in strTermSeg)
            {
                string strT = term.ToLower();
                if (hash.Contains(strT) == true)
                {
                    sb.Append("[mark]");
                    sb.Append(term);
                    sb.Append("[/mark]");
                }
                else
                {
                    sb.Append(term);
                }
            }

            sb.Replace("[/mark][mark]", "");
            sb.Replace("[/mark] [mark]", " ");
            return sb.ToString();
        }


        public List<ResultSentencePair> FilterBadSentencePair(ref List<SentencePair> spList, ref string strQuery, bool isMark)
        {
            List<ResultSentencePair> r = new List<ResultSentencePair>();
            if (isMark == true)
            {
                HashSet<string> hash = GetAllMarkWord(ref strQuery);
                foreach (SentencePair item in spList)
                {
                  //  if (sentencePairValidation.Validate(item.Language1Line) == true)
                  //  {
                        ResultSentencePair rsp = new ResultSentencePair();
                        rsp.Language1Line = LabelChineseSentence(item.Language1Line, ref hash);
                        rsp.Language2Line = LabelChineseSentence(item.Language2Line, ref hash);
                        rsp.strUrl = item.strUrl;
                        r.Add(rsp);
                  //  }
                }
            }
            else
            {   
                foreach (SentencePair item in spList)
                {
                //    if (sentencePairValidation.Validate(item.Language1Line) == true)
                //    {
                        ResultSentencePair rsp = new ResultSentencePair();
                        rsp.Language1Line = item.Language1Line;
                        rsp.Language2Line = item.Language2Line;
                        rsp.strUrl = item.strUrl;
                        r.Add(rsp);
                //    }
                }
            }

            return r;
        }

        public int GetTraditionalChineseByEnglish(string word, int startPageNo, int sizePerPage, bool isMark, string strUserId, out List<ResultSentencePair> rspList, out string strMessage)
        {
            int iStatus;
            iStatus = GetSentencePairByEnglish(word, startPageNo, sizePerPage, isMark, strUserId, out rspList, out strMessage);
            if (iStatus != 200)
            {
                return iStatus;
            }

            int i;
            for (i = 0; i < rspList.Count; i++)
            {
                rspList[i].Language2Line = chineseConvert.ConvertSimplifiedToTraditional(ref rspList[i].Language2Line);
            }

            return iStatus;
        }
        
        public int GetEnglishPairByTraditionalChinese(string word, int startPageNo, int sizePerPage, bool isMark, string strUserId, out List<ResultSentencePair> rspList, out string strMessage)
        {
            string scWord;

            scWord = chineseConvert.ConvertTraditionalToSimplified(ref word);
            int iStatus;
            iStatus = GetSentencePairByChinese(scWord, startPageNo, sizePerPage, isMark, strUserId, out rspList, out strMessage);
            if (iStatus != 200)
            {
                return iStatus;
            }

            int i;
            for (i = 0; i < rspList.Count; i++)
            {
                rspList[i].Language2Line = chineseConvert.ConvertSimplifiedToTraditional(ref rspList[i].Language2Line);
            }

            return iStatus;
        }

        public int GetSentencePairByJapanese(string word, int startPageNo, int sizePerPage, bool isMark, string strUserId, out List<ResultSentencePair> rspList, out string strMessage)
        {
            if (userAgent.IsInvalidate(ref strUserId) == false)
            {
                rspList = new List<ResultSentencePair>();
                strMessage = "您访问的次数过于频繁，由于网站资源受限，只得暂停您的访问权限，请在" + userAgent.GetAccessSpanHours().ToString() + "小时后再次访问。谢谢！";

                System.Diagnostics.EventLog.WriteEntry("Bilingual Sentence Search Engine Notice", "用户" + strUserId + "访问站点时间次数过于频繁，暂停其访问时间" + userAgent.GetAccessSpanHours().ToString() + "小时。");

                
                return 901;
            }

            List<SentencePair> spList;
            try
            {
               
                int iTopRecordNum = sizePerPage * (startPageNo + 1);
                spList = bilingualSentenceSearch.GetSentencePairByJapanese(word, iTopRecordNum);
                List<ResultSentencePair> tmpList = FilterBadSentencePair(ref spList, ref word, isMark);
                rspList = SplitSentencePairPage(startPageNo, sizePerPage, ref tmpList);


                //int iBadSentencePairs = sentencePairValidation.GetSentencePairNumOfQuery(ref word);
                //int iTopRecordNum = sizePerPage * (startPageNo + 1) + iBadSentencePairs;
                //spList = bilingualSentenceSearch.GetSentencePairByJapanese(word, iTopRecordNum);
                //List<ResultSentencePair> tmpList = FilterBadSentencePair(ref spList, ref word, isMark);
                //rspList = SplitSentencePairPage(startPageNo, sizePerPage, ref tmpList);
            }
            catch (System.Exception err)
            {
                System.Diagnostics.EventLog.WriteEntry("BilingualSentSearchService.GetSentencePairByEnglish", err.Message + "\n-----------------\n" + err.StackTrace + "\n");
                rspList = new List<ResultSentencePair>();
            }
            strMessage = "Successed";

            return 200;
        }


        public int GetSentencePairByEnglish(string word, int startPageNo, int sizePerPage, bool isMark, string strUserId, out List<ResultSentencePair> rspList, out string strMessage)
        {
            if (userAgent.IsInvalidate(ref strUserId) == false)
            {
                rspList = new List<ResultSentencePair>();
                strMessage = "您访问的次数过于频繁，由于网站资源受限，只得暂停您的访问权限，请在" + userAgent.GetAccessSpanHours().ToString() + "小时后再次访问。谢谢！";

                System.Diagnostics.EventLog.WriteEntry("Bilingual Sentence Search Engine Notice", "用户" + strUserId + "访问站点时间次数过于频繁，暂停其访问时间" + userAgent.GetAccessSpanHours().ToString() + "小时。");

                
                return 901;
            }

            List<SentencePair> spList;
            try
            {
                int iTopRecordNum = sizePerPage * (startPageNo + 1);
                spList = bilingualSentenceSearch.GetSentencePairByEnglish(word, iTopRecordNum);
                List<ResultSentencePair> tmpList = FilterBadSentencePair(ref spList, ref word, isMark);
                rspList = SplitSentencePairPage(startPageNo, sizePerPage, ref tmpList);

                //int iBadSentencePairs = sentencePairValidation.GetSentencePairNumOfQuery(ref word);
                //int iTopRecordNum = sizePerPage * (startPageNo + 1) + iBadSentencePairs;
                //spList = bilingualSentenceSearch.GetSentencePairByEnglish(word, iTopRecordNum);
                //List<ResultSentencePair> tmpList = FilterBadSentencePair(ref spList, ref word, isMark);
                //rspList = SplitSentencePairPage(startPageNo, sizePerPage, ref tmpList);
            }
            catch (System.Exception err)
            {
                System.Diagnostics.EventLog.WriteEntry("BilingualSentSearchService.GetSentencePairByEnglish", err.Message + "\n-----------------\n" + err.StackTrace + "\n");
                rspList = new List<ResultSentencePair>();
            }

            
            strMessage = "Successed";

            return 200;
        }
        
        public int GetSentencePairByChinese(string word, int startPageNo, int sizePerPage, bool isMark, string strUserId, out List<ResultSentencePair> rspList, out string strMessage)
        {
            if (userAgent.IsInvalidate(ref strUserId) == false)
            {
                rspList = new List<ResultSentencePair>();
                strMessage = "您访问的次数过于频繁，由于网站资源受限，只得暂停您的访问权限，请在" + userAgent.GetAccessSpanHours().ToString() + "小时后再次访问。谢谢！";

                System.Diagnostics.EventLog.WriteEntry("Bilingual Sentence Search Engine Notice", "用户" + strUserId + "访问站点时间次数过于频繁，暂停其访问时间" + userAgent.GetAccessSpanHours().ToString() + "小时。");

                
                return 901;
            }

            List<SentencePair> spList;
            try
            {
                int iTopRecordNum = sizePerPage * (startPageNo + 1);
                spList = bilingualSentenceSearch.GetSentencePairByChinese(word, iTopRecordNum);
                List<ResultSentencePair> tmpList = FilterBadSentencePair(ref spList, ref word, isMark);
                rspList = SplitSentencePairPage(startPageNo, sizePerPage, ref tmpList);

                //int iBadSentencePairs = sentencePairValidation.GetSentencePairNumOfQuery(ref word);
                //int iTopRecordNum = sizePerPage * (startPageNo + 1) + iBadSentencePairs;
                //spList = bilingualSentenceSearch.GetSentencePairByChinese(word, iTopRecordNum);
                //List<ResultSentencePair> tmpList = FilterBadSentencePair(ref spList, ref word, isMark);
                //rspList = SplitSentencePairPage(startPageNo, sizePerPage, ref tmpList);

                if (startPageNo == 0)
                {
                    da.WriteEntry(ref word, ref spList);
                }
            }
            catch (System.Exception err)
            {
                System.Diagnostics.EventLog.WriteEntry("BilingualSentSearchService.GetSentencePairByChinese", err.Message + "\n-----------------\n" + err.StackTrace + "\n");
                rspList = new List<ResultSentencePair>();
            }

         
            strMessage = "Successed";

            return 200;
        }

        private List<ResultSentencePair> SplitSentencePairPage(int startPageNo, int sizePerPage, ref List<ResultSentencePair> sentPair)
        {
            int startSentNum = startPageNo * sizePerPage;
            if (startSentNum > sentPair.Count)
            {
                return new List<ResultSentencePair>();
            }

            if (sentPair.Count < startSentNum + sizePerPage)
            {
                return sentPair.GetRange(startSentNum, sentPair.Count - startSentNum);
            }
            else
            {
                return sentPair.GetRange(startSentNum, sizePerPage);
            }
        }
    }
}
